package com.hzw.saas.web.app.ds.controller;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.hzw.saas.api.ds.*;
import com.hzw.saas.api.ds.bo.*;
import com.hzw.saas.api.ds.enums.ClientTypeEnum;
import com.hzw.saas.api.ds.query.HeartbeatQuery;
import com.hzw.saas.api.ds.query.OnlineDeviceQuery;
import com.hzw.saas.api.ds.query.RankingQuery;
import com.hzw.saas.api.ds.query.SyncConfigQuery;
import com.hzw.saas.api.hpc.IHpcAccountIncreaseService;
import com.hzw.saas.api.hpc.IHpcAccountProviderService;
import com.hzw.saas.api.hpc.IHpcAccountUserService;
import com.hzw.saas.api.hpc.bo.HpcAccountIdProviderBo;
import com.hzw.saas.api.hpc.bo.HpcAccountInfoBo;
import com.hzw.saas.api.hpc.bo.HpcAccountUserBo;
import com.hzw.saas.api.hpc.enums.HpcProviderType;
import com.hzw.saas.api.product.ILicenseUserService;
import com.hzw.saas.api.product.dto.UserProductAuthDto;
import com.hzw.saas.api.storage.IStorageService;
import com.hzw.saas.api.storage.bo.StorageCapacityBO;
import com.hzw.saas.api.user.IUserProfileService;
import com.hzw.saas.api.user.bo.DsUserAccountBo;
import com.hzw.saas.common.config.annotation.SysLog;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.security.utils.SecurityUtils;
import com.hzw.saas.common.util.Arith;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.service.ds.service.OnlineLevelInfoServiceImpl;
import com.hzw.saas.service.hpc.service.IHpcAccountSlurmService;
import com.hzw.saas.service.hpc.service.IQingCloudService;
import com.hzw.saas.service.hpc.service.bo.SlurmAccountBO;
import com.hzw.saas.web.app.ds.dto.DsHpcAccountDto;
import com.hzw.saas.web.app.ds.dto.DsUserInfoDto;
import com.hzw.saas.web.app.ds.param.DsHeartBeatParam;
import io.swagger.annotations.*;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.constraints.Min;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Validated
@RestController
@RequestMapping("access/ds")
@Api(tags = "应用接入-Device Studio")
public class DsController {

    @Resource
    private ISyncConfigService syncConfigService;
    @Resource
    private IMarketingAdService marketingAdService;
    @Resource
    private IHeartbeatService heartbeatService;
    @Resource
    private IHeartbeatLogService heartbeatLogService;
    @Resource
    private IOnlineLevelInfoService onlineLevelInfoService;
    @Resource
    private IUserProfileService userProfileService;
    @Resource
    private ILicenseUserService licenseUserService;
    @Resource
    private IStorageService storageService;
    @Resource
    private IHpcAccountUserService accountUserService;
    @Resource
    private IHpcAccountIncreaseService increaseService;
    @Resource
    private IHpcAccountSlurmService slurmService;
    @Resource
    private IQingCloudService qingCloudService;
    @Resource
    private IHpcAccountProviderService providerService;

    public final static String DEFAULT_AVATAR = "/avatars/1.png";

    @PostMapping("heartbeat")
    @ApiOperation(value = "(登陆后)心跳", notes = "心跳")
    @ApiOperationSort(1)
    public ResponseEntity<HeartbeatBo> getHeartbeat(@RequestBody DsHeartBeatParam dsHeartBeatParam) {
        HeartbeatQuery heartbeatQuery = MapperUtil.nf().map(dsHeartBeatParam, HeartbeatQuery.class);
        heartbeatQuery.setUserId(SecurityUtils.getUserId()).setClientType(ClientTypeEnum.ds);
        HeartbeatBo heartbeat = heartbeatService.heartbeat(heartbeatQuery);
        return ResponseEntity.ok(heartbeat);
    }

    @GetMapping("user")
    @SysLog
    @ApiOperation(value = "获取用户信息")
    @ApiOperationSort(2)
    public ResponseEntity<DsUserInfoDto> getDsUserInfo() {
        String userId = SecurityUtils.getUserId();
        // 用户基本信息
        DsUserAccountBo dsUserAccount = userProfileService.getDsUserAccount(userId, ClientTypeEnum.ds);
        DsUserInfoDto dsUserInfoDto = MapperUtil.nf().map(dsUserAccount, DsUserInfoDto.class);
        dsUserInfoDto.setAvatar(StrUtil.isBlank(dsUserInfoDto.getAvatar()) ? DEFAULT_AVATAR : dsUserInfoDto.getAvatar());
        if (Objects.isNull(dsUserAccount.getDsLevel())) {
            dsUserInfoDto.setDsLevel(1)
                    .setDsLevelCurrentEx(0L)
                    .setDsLevelUpgradeEx(OnlineLevelInfoServiceImpl.LEVEL_ONE.longValue());
            onlineLevelInfoService.initDsUserLevel(userId);
        }
        // 可用计算机软件
        Integer[] cloudType = {1, 2, 4};
        List<UserProductAuthDto> products = licenseUserService.listProducts(userId, cloudType);
        dsUserInfoDto.setUserProductAuthDtoList(products);
        // 云空间信息
        StorageCapacityBO storageCapacityBO = storageService.getStorageCapacity(userId, false);
        dsUserInfoDto.setStorageCapacityBO(storageCapacityBO);
        return ResponseEntity.ok(dsUserInfoDto);
    }

    @GetMapping("hpc-accounts")
    @SysLog
    @ApiOperation(value = "超算账号与算力")
    @ApiOperationSort(3)
    public ResponseEntity<List<DsHpcAccountDto>> getHpcAccounts() {
        Date startDate = new Date();
        // hpcs/accounts
        List<HpcAccountUserBo> records = accountUserService.getUsableListByUserIdPage(PageParam.getBigPageParam(),
                SecurityUtils.getUserId(), null, false).getRecords();

        Set<String> hpcAccountIds = records.stream().map(HpcAccountUserBo::getHpcAccountId).collect(Collectors.toSet());
        Map<String, HpcAccountIdProviderBo> cacheMap = providerService.getByHpcAccountIds(hpcAccountIds, HpcProviderType.QY)
                .stream()
                .collect(Collectors.toMap(HpcAccountIdProviderBo::getHpcAccountId, Function.identity()));

        List<DsHpcAccountDto> dsHpcAccountDtoList = records.stream()
                .map(accountUserBo -> {
                    double sumIncrease = increaseService.getSumIncreaseByStartDate(Collections.singletonList(accountUserBo.getHpcAccountRecordId()), startDate);
                    SlurmAccountBO slurmAccount = slurmService.getSlurmAccount(accountUserBo.getSlurmAccount());
                    HpcAccountInfoBo hpcAccountInfoBo = MapperUtil.nf().map(accountUserBo, HpcAccountInfoBo.class)
                            .setAccountId(accountUserBo.getPid())
                            .setExpireDate(accountUserBo.getExpireTime())
                            .setRegisterDate(accountUserBo.getCreateTime())
                            .setSubExpireDate(accountUserBo.getSubExpireTime())
                            .setHpcAccount(accountUserBo.getHpcAccountSnapshot())
                            .setHpcAmount(NumberUtil.round(Arith.add(accountUserBo.getCoreTimeBalanceTotal(), sumIncrease), 2).doubleValue())
                            .setHpcBalance(NumberUtil.round(Arith.add(accountUserBo.getCoreTimeBalance(), sumIncrease), 2).doubleValue());

                    DsHpcAccountDto dsHpcAccountDto = new DsHpcAccountDto()
                            .setSlurmAccountBO(slurmAccount)
                            .setHpcAccountInfoBo(hpcAccountInfoBo);

                    if (cacheMap.containsKey(accountUserBo.getHpcAccountId())) {
                        dsHpcAccountDto.setClusterUsageBO(qingCloudService.getCacheClusterUsage(cacheMap.get(accountUserBo.getHpcAccountId())));
                    }
                    return dsHpcAccountDto;
                })
                .collect(Collectors.toList());
        return ResponseEntity.ok(dsHpcAccountDtoList);
    }

    @PostMapping("config")
    @ApiOperation(value = "更新同步配置", notes = "更新同步配置")
    @ApiOperationSort(4)
    public ResponseEntity<Boolean> modifyDsSyncConfig(@RequestBody SyncConfigBo dsSyncConfigBo) {
        SyncConfigQuery syncConfigQuery = MapperUtil.nf().map(dsSyncConfigBo, SyncConfigQuery.class);
        syncConfigQuery.setUserId(SecurityUtils.getUserId())
                .setClientType(ClientTypeEnum.ds);
        Boolean result = syncConfigService.modifySyncConfig(syncConfigQuery);
        return ResponseEntity.ok(result);
    }

    @GetMapping("config")
    @ApiOperation(value = "获取同步配置", notes = "获取同步配置")
    @ApiOperationSort(5)
    public ResponseEntity<SyncConfigBo> getDsSyncConfig() {
        SyncConfigQuery syncConfigQuery = new SyncConfigQuery()
                .setUserId(SecurityUtils.getUserId())
                .setClientType(ClientTypeEnum.ds);
        SyncConfigBo dsSyncConfigBo = syncConfigService.getSyncConfig(syncConfigQuery);
        return ResponseEntity.ok(dsSyncConfigBo);
    }

    @PostMapping("online-devices")
    @ApiOperation(value = "获取在线设备信息", notes = "获取在线设备信息")
    @ApiOperationSort(6)
    public ResponseEntity<List<OnlineDeviceBo>> getOnlineDevices() {
        OnlineDeviceQuery onlineDeviceQuery = new OnlineDeviceQuery()
                .setUserId(SecurityUtils.getUserId())
                .setClientType(ClientTypeEnum.ds);
        List<OnlineDeviceBo> onlineDeviceBos = heartbeatLogService.getOnlineDevices(onlineDeviceQuery);
        return ResponseEntity.ok(onlineDeviceBos);
    }

    @GetMapping("ad")
    @ApiOperation(value = "获取营销展示", notes = "获取营销展示")
    @ApiOperationSort(7)
    public ResponseEntity<List<MarketingAdBo>> getDsAd() {
        List<MarketingAdBo> dsMarketingAdBos = marketingAdService.getMarketingAds(ClientTypeEnum.ds);
        return ResponseEntity.ok(dsMarketingAdBos);
    }

    @GetMapping("ranking/{size}")
    @ApiOperation(value = "获取排行榜", notes = "获取排行榜")
    @ApiImplicitParams(
            @ApiImplicitParam(name = "size", value = "排行榜前size", dataType = "Integer", paramType = "path", required = true)
    )
    @ApiOperationSort(8)
    public ResponseEntity<RankingBo> getDsRanking(@PathVariable @Min(0) Integer size) {
        RankingQuery rankingQuery = new RankingQuery()
                .setSize(size)
                .setClientType(ClientTypeEnum.ds)
                .setUserId(SecurityUtils.getUserId());
        RankingBo rankingBo = onlineLevelInfoService.getRankingList(rankingQuery);
        rankingBo.getRankingList().forEach(r -> r.setAvatar(StrUtil.isBlank(r.getAvatar()) ? DEFAULT_AVATAR : r.getAvatar()));
        RankingNumBo currentUserRankingInfo = rankingBo.getCurrentUserRankingInfo();
        if (Objects.isNull(currentUserRankingInfo)) {
            initCurrentUserLevelInfo(rankingBo);
        }
        currentUserRankingInfo.setAvatar(StrUtil.isBlank(currentUserRankingInfo.getAvatar()) ? DEFAULT_AVATAR : currentUserRankingInfo.getAvatar());
        return ResponseEntity.ok(rankingBo);
    }

    private void initCurrentUserLevelInfo(RankingBo rankingBo) {
        DsUserAccountBo dsUserAccount = userProfileService.getDsUserAccount(SecurityUtils.getUserId(), ClientTypeEnum.ds);
        RankingNumBo rankingNumBo = new RankingNumBo();
        rankingNumBo.setRankNum((long) onlineLevelInfoService.countByType(ClientTypeEnum.ds) + 1);
        rankingNumBo.setUserName(dsUserAccount.getUserName());
        rankingNumBo.setAvatar(dsUserAccount.getAvatar());
        rankingNumBo.setDsTotalEx(0L);
        rankingNumBo.setDsLevel(1);
        rankingNumBo.setDsLevelCurrentEx(0L);
        rankingBo.setCurrentUserRankingInfo(rankingNumBo);
    }

}
